import { DataContextFactory } from './../domain/fbsDataContext';
import { Device } from "../domain/model";
import { ServiceException } from "./serviceException";
import { Guid, Logger, ObjectCopier, intersectionArray } from "../common/utils";
import { Transaction } from "tiny-entity";

export class DeviceService {
    private get ctx() {
        return DataContextFactory.GetDataContext();
    }

    constructor() {
    }

    public async findDeviceByAdsId(adsId: string) {
        const devcies = await this.ctx.Device.ToList();
        const devcie = devcies.find(x => x.ads.adsId == adsId);
        return devcie;
    }

    private async deleteDevice(device: Device) {
        await this.ctx.Delete(device)
    }

    public async generateDevice(device: Device) {
        delete (<any>device).user
        delete (<any>device).terminal
        const olDdevice = await this.findDeviceByAdsId(device.ads.adsId);
        if (olDdevice) {
            await this.deleteDevice(olDdevice);
        }
        device.id = Guid.GetGuid();
        let newDevice = new Device()
        newDevice = newDevice.clone(device, newDevice);
        const generatedDevice: Device = await this.ctx.Create(newDevice);
        return {
            generatedDevice,
            deletedDevice: olDdevice
        }
    }



    public async addDevice(device: Device) {
        const olDdevice = await this.ctx.Device.First(x => x.id == device.id, ["device.id"], [device.id])
        if (olDdevice) {
            this.ctx.Delete(olDdevice);
        }
        let newDevice = new Device()
        newDevice = newDevice.clone(device, newDevice);
        return await this.ctx.Create(newDevice)
    }

    public queryDevices(query?: {
        deviceType?: string,
        id?: string
    }) {
        if (!query) {
            return this.ctx.Device.ToList();
        }
        const predicates = this.ctx.Device;
        if (typeof query.deviceType != "undefined") {
            predicates.Where(x => x.deviceType == query.deviceType, ["query.deviceType"], [query.deviceType]);
        }
        if (typeof query.id != "undefined") {
            predicates.Where(x => x.id == query.id, ["query.id"], [query.id]);
        }
        return predicates.ToList()
    }

    public async mergeDevices(id, deviceIds: Array<string>) {
        const device = await this.ctx.Device.First(x => x.id == id, ["id"], [id]);
        if (!device) {
            throw new ServiceException(this, "未找到主设备")
        }
        const intersectDeviceIds = device.transferIn && intersectionArray(device.transferIn, deviceIds);
        if (intersectDeviceIds && intersectDeviceIds.length > 0) {
            throw new ServiceException(this, intersectDeviceIds.map(x => x.id).join("、") + "已有转移记录");
        }
        let resDevices: Array<Device> = [];
        for (let i = 0, l = deviceIds.length; i < l; i++) {
            const deviceId = deviceIds[i];
            const resDevice = await this.ctx.Device.First(x => x.id == deviceId, ["deviceId"], [deviceId]);
            if (!resDevice) {
                throw new ServiceException(this, deviceIds[i] + "未找到");
            }
            resDevices.push(resDevice);
        }
        const allDeviceIds = deviceIds.concat(id);
        resDevices.forEach(v => {
            if (!v.transferIn) {
                v.transferIn = [];
            }
            v.transferIn = v.transferIn.concat(allDeviceIds.filter(x => x != v.id));
        })
        for (let resDevice of resDevices) {
            await this.ctx.Update(resDevice)
        }
        if (!device.transferIn) {
            device.transferIn = [];
        }
        device.transferIn = device.transferIn.concat(allDeviceIds.filter(x => x != device.id));
        return await this.ctx.Update(device)
    }


    public async unmergeDevices(id, deviceIds) {
        const device = await this.ctx.Device.First(x => x.id == id, ["id"], [id]);
        if (!device) {
            throw new ServiceException(this, "未找到主设备")
        }
        if (!(device.transferIn && device.transferIn.length > 0)) {
            throw new ServiceException(this, device.id + "的transferIn没有合并记录");
        }
        let resDevices: Array<Device> = [];
        for (let i = 0, l = deviceIds.length; i < l; i++) {
            const deviceId = deviceIds[i];
            const resDevice = await this.ctx.Device.First(x => x.id == deviceId, ["deviceId"], [deviceId]);
            if (!resDevice) {
                throw new ServiceException(this, deviceIds[i] + "未找到");
            }
            if (!(resDevice.transferIn && resDevice.transferIn.length > 0)) {
                throw new ServiceException(this, deviceIds[i] + "的transferIn没有合并记录");
            }
            resDevices.push(resDevice);
        }
        resDevices.forEach(v => {
            v.transferIn = v.transferIn.filter(x => deviceIds.indexOf(id) > -1)
        })
        for (let resDevice of resDevices) {
            await this.ctx.Update(resDevice)
        }
        device.transferIn = device.transferIn.filter(x => deviceIds.indexOf(x) == -1)
        return await this.ctx.Update(device)
    }

    public async changeDeviceKitchenSolution(id, KitchenSolutionId) {
        const device = await this.getDeviceById(id);
        if (!device) {
            throw new ServiceException(this, id + "的设备没有找到");
        }
        device.kitchenSolutionId = KitchenSolutionId;
        await this.ctx.Update(device);
        return {
            device
        }
    }

    private async getDeviceById(id) {
        const device = await this.ctx.Device.First(x => x.id == id, ["id"], [id]);
        return device;
    }

    private async getDevicesByIds(ids: string[]) {
        //.Where(x => ids.indexOf(x.id) > -1)
        const devices = await this.ctx.Device.Contains(x => x.id, ids).ToList();
        return devices;
    }

    public async transferDevice(id: string, transferOutId: string) {
        const device = await this.getDeviceById(id);
        if (!device) {
            throw new ServiceException(this, id + "的设备没有找到");
        }
        if (device.transferOut) {
            throw new ServiceException(this, "已经转移到" + transferOutId);
        }
        if (device.transferIn && device.transferIn.length > 0) {
            throw new ServiceException(this, "已有合并记录");
        }
        const transferOutDevice = await this.getDeviceById(transferOutId);
        if (!transferOutDevice) {
            throw new ServiceException(this, transferOutId + "的设备没有找到");
        }
        device.transferOut = transferOutId;
        transferOutDevice.transferIn || (transferOutDevice.transferIn = []);
        transferOutDevice.transferIn.push(id);
        await this.ctx.Update(transferOutDevice);
        await this.ctx.Update(device);
        return {
            masterDevice: device,
            transferOutDevice
        }
    }

    public async cancelTransferDevice(id: string, transferOutId: string) {
        const device = await this.getDeviceById(id);
        if (!device) {
            throw new ServiceException(this, id + "的设备没有找到");
        }
        if (device.transferOut != transferOutId) {
            throw new ServiceException(this, transferOutId + "没有转移");
        }
        const transferOutDevice = await this.getDeviceById(transferOutId);
        if (!transferOutDevice) {
            throw new ServiceException(this, transferOutId + "的设备没有找到");
        }
        if (transferOutDevice.transferIn.indexOf(id) == -1) {
            throw new ServiceException(this, transferOutId + "没有合并记录");
        }
        device.transferOut = "";
        transferOutDevice.transferIn.splice(transferOutDevice.transferIn.indexOf(id), 1);
        await this.ctx.Update(transferOutDevice);
        await this.ctx.Update(device);
        return {
            masterDevice: device,
            transferOutDevice
        }
    }

}